module(..., package.seeall)

cw_bat = {usb_online = 0, voltage = 0, capacity = 0}

local i2cId = 2
local i2cSlaveAddr = 0x62

-- CW2015 寄存器定义
local REG_VERSION = 0x00
local REG_VCELL = 0x02
local REG_SOC = 0x04
local REG_RRT_ALERT = 0x06
local REG_CONFIG = 0x08
local REG_MODE = 0x0A
local REG_BATINFO = 0x10

local MODE_SLEEP_MASK = 0xC0
local MODE_SLEEP = 0xC0
local MODE_NORMAL = 0x00
local MODE_QUICK_START = 0x30
local MODE_RESTART = 0x0F

local CONFIG_UPDATE_FLG = 0x02
local ATHD = 0x00

-- CW2015 参数定义
local BATTERY_UP_MAX_CHANGE = 720
local BATTERY_DOWN_MIN_CHANGE = 60
local BATTERY_DOWN_MIN_CHANGE_SLEEP = 1800
local SIZE_BATINFO = 64

local UI_FULL = 100

local cw_bat_config_info = {
    0x15, 0x7C, 0x7A, 0x72, 0x56, 0x56, 0x63, 0x5C, 0x54, 0x55, 0x5A, 0x55,
    0x61, 0x63, 0x53, 0x41, 0x34, 0x2C, 0x28, 0x2B, 0x32, 0x43, 0x55, 0x64,
    0x56, 0x49, 0x0A, 0x3E, 0x0A, 0x14, 0x4D, 0x6A, 0x73, 0x74, 0x7D, 0x81,
    0x3B, 0x1A, 0x70, 0x3C, 0x01, 0x52, 0x52, 0x87, 0x8F, 0x91, 0x94, 0x52,
    0x82, 0x8C, 0x92, 0x96, 0x7E, 0xD0, 0xE6, 0xCB, 0x2F, 0x7D, 0x72, 0xA5,
    0xB5, 0xC1, 0xE1, 0x89
}

local no_charger_full_jump = 0
local allow_no_charger_full = 0
local allow_charger_always_zero = 0
local if_quickstart = 0
local reset_loop = 0

local function cw_write(data) i2c.send(i2cId, i2cSlaveAddr, data) end
local function cw_read(data, num)
    i2c.send(i2cId, i2cSlaveAddr, data)
    local revData = i2c.recv(i2cId, i2cSlaveAddr, num)
    return revData:byte()
end

local function cw_update_config_info()
    local reg_val = cw_read(REG_MODE, 1)
    if bit.band(reg_val, MODE_SLEEP_MASK) == MODE_SLEEP then return 2 end
    for i = 1, SIZE_BATINFO do
        reg_val = cw_bat_config_info[i]
        cw_write({REG_BATINFO + i - 1, reg_val})
    end
    for i = 1, SIZE_BATINFO do
        reg_val = cw_read(REG_BATINFO + i - 1, 1)
        if reg_val ~= cw_bat_config_info[i] then return 3 end
    end

    reg_val = cw_read(REG_CONFIG, 1)
    reg_val = bit.bor(reg_val, CONFIG_UPDATE_FLG)
    reg_val = bit.band(reg_val, 0x07)
    reg_val = bit.bor(reg_val, ATHD)
    cw_write({REG_CONFIG, reg_val})

    cw_write({REG_MODE, MODE_RESTART})
    sys.wait(10)
    cw_write({REG_MODE, MODE_NORMAL})

    return 0
end

local function cw_config()
    local ret = 0
    cw_write({REG_MODE, MODE_NORMAL})
    local reg_val = cw_read(REG_CONFIG, 1)

    if bit.band(reg_val, 0xF8) ~= ATHD then
        reg_val = bit.band(reg_val, 0x07)
        reg_val = bit.bor(reg_val, ATHD)
        cw_write({REG_CONFIG, reg_val})
    end
    reg_val = cw_read(REG_CONFIG, 1)
    if not bit.band(reg_val, CONFIG_UPDATE_FLG) then
        ret = cw_update_config_info()
        if ret > 0 then return ret end
    else
        local index = 1
        for i = 1, SIZE_BATINFO do
            index = i
            reg_val = cw_read(REG_BATINFO + i - 1, 1)
            if reg_val ~= cw_bat_config_info[i] then break end
        end
        if index ~= SIZE_BATINFO then
            ret = cw_update_config_info()
            if ret > 0 then return ret end
        end
        index = 1
        for i = 1, 30 do
            index = i
            reg_val = cw_read(REG_SOC, 1)
            if reg_val <= 100 then break end
            sys.wait(100)
        end
        if index >= 30 then
            cw_write({REG_MODE, MODE_SLEEP})
            return 4
        end
    end

    return 0
end

local function cw_por()
    cw_write({REG_MODE, MODE_SLEEP})
    sys.wait(10)
    cw_write({REG_MODE, MODE_NORMAL})
    sys.wait(10)
    cw_config()
end

local function cw_set_athd(new_athd)
    new_athd = bit.lshift(new_athd, 3)
    local reg_val = 0x00
    reg_val = bit.band(reg_val, 0x07)
    reg_val = bit.bor(reg_val, new_athd)
    cw_write({REG_CONFIG, reg_val})
end

local function cw_get_capacity()
    local allow_capacity = 0
    local reg_val = {0, 0}
    reg_val[0] = cw_read(REG_SOC, 1)
    reg_val[1] = cw_read(REG_SOC + 1, 1)

    local real_SOC = reg_val[0]
    local digit_SOC = reg_val[1]
    local cw_capacity = real_SOC

    if cw_capacity < 0 or cw_capacity > 100 then
        reset_loop = reset_loop + 1
        if reset_loop > 5 then
            cw_por()
            reset_loop = 0
        end
        return cw_bat["capacity"]
    else
        reset_loop = 0
    end

    if (cw_bat["usb_online"] == 1 and cw_capacity == cw_bat["capacity"] - 1) or
        (cw_bat["usb_online"] == 0 and cw_capacity == cw_bat["capacity"] + 1) then
        if not ((cw_capacity == 0 and cw_bat["capacity"] <= 2) or
            (cw_capacity == 100 and cw_bat["capacity"] == 99)) then
            cw_capacity = cw_bat["capacity"]
        end
    end

    if (cw_bat["usb_online"] == 1) and (cw_capacity >= 95) and
        (cw_capacity <= cw_bat["capacity"]) then
        allow_no_charger_full = allow_no_charger_full + 1
        if allow_no_charger_full >= BATTERY_UP_MAX_CHANGE then
            allow_capacity = cw_bat["capacity"] + 1
            if allow_capacity <= 100 then
                cw_capacity = allow_capacity
            else
                cw_capacity = 100
            end
            no_charger_full_jump = 1
            allow_no_charger_full = 0
        elseif cw_capacity <= cw_bat["capacity"] then
            cw_capacity = cw_bat["capacity"]
        end
    elseif (cw_bat["usb_online"] == 0) and (cw_capacity <= cw_bat["capacity"]) and
        (cw_capacity >= 90) and (no_charger_full_jump == 1) then
        if cw_bat["usb_online"] == 0 then
            allow_no_charger_full = allow_no_charger_full + 1
        end
        if allow_no_charger_full >= BATTERY_DOWN_MIN_CHANGE then
            allow_capacity = cw_bat["capacity"] - 1
            allow_no_charger_full = 0
            if cw_capacity >= allow_capacity then
                no_charger_full_jump = 0
            else
                if allow_capacity > 0 then
                    cw_capacity = allow_capacity
                else
                    cw_capacity = 0
                end
            end
        elseif cw_capacity <= cw_bat["capacity"] then
            cw_capacity = cw_bat["capacity"]
        end
    else
        allow_no_charger_full = 0
    end

    if cw_bat["usb_online"] > 0 and cw_capacity == 0 then
        allow_charger_always_zero = allow_charger_always_zero + 1
        if allow_charger_always_zero >= BATTERY_DOWN_MIN_CHANGE_SLEEP and
            if_quickstart == 0 then
            cw_por()
            if_quickstart = 1
            allow_charger_always_zero = 0
        end
    elseif if_quickstart == 1 and cw_bat["usb_online"] == 0 then
        if_quickstart = 0
    end

    local UI_SOC = real_SOC * 256 + digit_SOC
    UI_SOC = UI_SOC * 100 / (UI_FULL * 256)
    local remainder = real_SOC * 256 + digit_SOC
    remainder = (remainder * 100 * 100 / (UI_FULL * 256)) % 100

    if UI_SOC >= 100 then
        UI_SOC = 100
    elseif UI_SOC == 0 and remainder <= 10 then
        UI_SOC = 0
    else
        if (remainder > 80 or remainder < 20) and
            (UI_SOC >= cw_bat["capacity"] - 1) and
            (UI_SOC <= cw_bat["capacity"] + 1) then
            UI_SOC = cw_bat["capacity"]
        end
    end

    return UI_SOC
end

local function cw_get_vcell()
    local reg_val = {0, 0}
    local ad_value = 0
    local ad_buff = 0
    local ad_value_min = 0
    local ad_value_max = 0

    for get_ad_times = 1, 3 do
        reg_val[0] = cw_read(REG_VCELL, 1)
        reg_val[1] = cw_read(REG_VCELL + 1, 1)

        ad_buff = bit.lshift(reg_val[0], 8) + reg_val[1]

        if get_ad_times == 1 then
            ad_value_min = ad_buff
            ad_value_max = ad_buff
        end

        if ad_buff < ad_value_min then ad_value_min = ad_buff end
        if ad_buff > ad_value_max then ad_value_max = ad_buff end

        ad_value = ad_value + ad_buff
    end

    ad_value = ad_value - ad_value_min
    ad_value = ad_value - ad_value_max
    ad_value = ad_value * 305 / 1000
    return ad_value
end

function cw_release_alrt_pin()
    local reg_val = cw_read(REG_RRT_ALERT, 1)
    local alrt = bit.band(reg_val, 0x80)
    reg_val = bit.band(reg_val, 0x7F)
    cw_write({REG_RRT_ALERT, reg_val})
    return alrt
end

local function cw_update_capacity()
    local cw_capacity = cw_get_capacity()
    if (cw_capacity >= 0 and cw_capacity <= 100) and
        (cw_bat["capacity"] ~= cw_capacity) then
        cw_bat["capacity"] = cw_capacity
    end
    log.debug("capacity", cw_bat["capacity"])
end

local function cw_update_vol()
    local cw_voltage = cw_get_vcell()
    if cw_voltage == 1 then
        cw_bat["voltage"] = cw_bat["voltage"]
    elseif cw_voltage * 2 ~= cw_bat["voltage"] then
        cw_bat["voltage"] = cw_voltage * 2
    end
    log.debug("voltage", cw_bat["voltage"])
end

local function cw_init()
    if i2c.setup(i2cId, i2c.SLOW) ~= i2c.SLOW then
        log.error("I2c.init", "fail")
        return
    end
    log.info("I2c.init", "success")
    cw_config()
end

sys.taskInit(function()
    sys.wait(5000)
    cw_init()
    while true do
        -- 更新电池容量
        cw_update_capacity()
        -- 更新电池电压
        cw_update_vol()
        sys.wait(1000)
    end
end)
